home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / wais / ui / document.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  18KB  |  758 lines

  1. /* 
  2.   WIDE AREA INFORMATION SERVER SOFTWARE:
  3.    No guarantees or restrictions.  See the readme file for the full standard
  4.    disclaimer.
  5.  
  6.    This is part of the shell user-interface tools for the WAIS software.
  7.    Do with it as you please.
  8.  
  9.    jonathan@Think.COM
  10.  *
  11.  * $Log:    document.c,v $
  12.  * Revision 1.10  92/05/07  14:50:27  jonathan
  13.  * Fixed listing for sections starting at 0.
  14.  * 
  15.  * Revision 1.9  92/04/02  14:23:36  jonathan
  16.  * fleshed out copy_cretdoc.
  17.  * 
  18.  * Revision 1.8  92/04/01  17:16:20  jonathan
  19.  * Added some copying functions.
  20.  * 
  21.  * Revision 1.7  92/03/17  14:36:40  jonathan
  22.  * Cleaned up for use with X interface as well.
  23.  * 
  24.  * Revision 1.6  92/03/08  09:13:13  jonathan
  25.  * strip lf from headlines.
  26.  * 
  27.  */
  28.  
  29. #ifndef lint
  30. static char *RCSid = "$Header: /tmp_mnt/net/quake/proj/wais/wais-8-b5/ui/RCS/document.c,v 1.10 92/05/07 14:50:27 jonathan Exp $";
  31. #endif
  32.  
  33. #include "wais.h"
  34. #include "util.h"
  35. #include "globals.h"
  36. #include "document.h"
  37.  
  38.  
  39. static void** copyList(list)
  40. void **list;
  41. {
  42.   void **result = NULL;
  43.   void **l1, **l2;
  44.   long i;
  45.  
  46.   if(list != NULL) {
  47.     for(l1 = list, i = 0; *l1 != NULL; i++, l1++);
  48.       if((result = (void**)s_malloc((1+i)*sizeof(void*))) != NULL) {
  49.       for(l1 = list, l2 = result; *l1 != NULL; l1++, l2++) {
  50.     *l2 = s_strdup(*l1);
  51.       }
  52.       result[i] = NULL;
  53.     }
  54.   }
  55.   return result;
  56. }
  57.       
  58. static void freeList(list)
  59. void **list;
  60. {
  61.   void** l = list;
  62.   while(*l != NULL) {
  63.     s_free(*l);
  64.     l++;
  65.   }
  66.   s_free(list);
  67. }
  68.  
  69. static void strip_lf(line)
  70. char *line;
  71. {
  72.   long i;
  73.  
  74.   if (line!=NULL) {
  75.     do {
  76.       if (*line=='\r' || *line=='\n') *line='_';
  77.     } while(*line++);
  78.   }
  79. }
  80.     
  81. static void
  82. setdate(date, source)
  83. char *date, *source;
  84. {
  85.   date[8] = 0;
  86.   date[2] = date[5] = '/';
  87.   date[0] = source[2];
  88.   date[1] = source[3];
  89.   date[3] = source[4];
  90.   date[4] = source[5];
  91.   date[6] = source[0];
  92.   date[7] = source[1];
  93. }
  94.  
  95. void
  96. freeItemList(list)
  97. char **list;
  98. {
  99.   char **temp;
  100.  
  101.   temp = list;
  102.  
  103.   while(*temp != NULL) {
  104.     s_free(*temp);
  105.     temp++;
  106.   }
  107.  
  108.   s_free (list);
  109. }
  110.  
  111. char **
  112. buildDocumentItemList(doclist, scorep)
  113. DocList doclist;
  114. Boolean scorep;
  115. {
  116.   char **result, date[9];
  117.   int num, i;
  118.   DocList doc;
  119.  
  120.   /* find the length of the doclist in the question */
  121.  
  122.   for(num = 0, doc = doclist;
  123.       doc != NULL && doc->thisDoc != NULL;
  124.       num++, doc = doc->nextDoc);
  125.  
  126.   result = (char**) s_malloc(1+num*sizeof(char*));
  127.   result[num] = NULL;
  128.   if(num > 0)
  129.     for(i = 0, doc = doclist; i<num; i++, doc = doc->nextDoc) {
  130.       if(doc->thisDoc != NULL) {
  131.     if(scorep == TRUE) {
  132.       result[i] = s_malloc(strlen(doc->thisDoc->doc->headline)+26);
  133.       if ((doc->thisDoc->doc->date == NULL) ||
  134.           (strcmp(doc->thisDoc->doc->date, "0") == 0)) {
  135.         if (doc->thisDoc->doc->numChars > 1024)
  136.           sprintf(result[i], "%5d %4.1fK %s", 
  137.               doc->thisDoc->rawScore,
  138.               ((float)doc->thisDoc->doc->numChars/1024.0),
  139.               doc->thisDoc->doc->headline);
  140.         else
  141.           sprintf(result[i], "%5d %5d %s", 
  142.               doc->thisDoc->rawScore,
  143.               doc->thisDoc->doc->numChars,
  144.               doc->thisDoc->doc->headline);
  145.       }
  146.       else {
  147.         setdate(date, doc->thisDoc->doc->date);
  148.         if (doc->thisDoc->doc->numChars > 1024)
  149.           sprintf(result[i], "%5d %4.1fK (%s) %s",
  150.               doc->thisDoc->rawScore, 
  151.               ((float)doc->thisDoc->doc->numChars/1024.0),
  152.               date,
  153.               doc->thisDoc->doc->headline);
  154.         else
  155.           sprintf(result[i], "%5d %4d (%s) %s",
  156.               doc->thisDoc->rawScore, 
  157.               doc->thisDoc->doc->numChars,
  158.               date,
  159.               doc->thisDoc->doc->headline);
  160.         
  161.       }
  162.     }
  163.     else {
  164.       result[i] = s_malloc(strlen(doc->thisDoc->doc->headline)+30);
  165.       if(doc->thisDoc->end > 0) {
  166.         if ((doc->thisDoc->doc->date != NULL) &&
  167.         (strcmp(doc->thisDoc->doc->date, "0") != 0)) {
  168.           setdate(date, doc->thisDoc->doc->date);
  169.           sprintf(result[i], "[%d,%d] (%s) %s", 
  170.               doc->thisDoc->start, doc->thisDoc->end, date,
  171.               doc->thisDoc->doc->headline);
  172.         }
  173.         else {
  174.           sprintf(result[i], "[%d,%d] %s", 
  175.               doc->thisDoc->start, doc->thisDoc->end,
  176.               doc->thisDoc->doc->headline);
  177.         }
  178.       }
  179.       else
  180.         if ((doc->thisDoc->doc->date != NULL) &&
  181.         (strcmp(doc->thisDoc->doc->date, "0") != 0)) {
  182.           setdate(date, doc->thisDoc->doc->date);
  183.           sprintf(result[i], "(%s) %s",
  184.               date, doc->thisDoc->doc->headline);
  185.         }
  186.         else {
  187.           sprintf(result[i], "%s", doc->thisDoc->doc->headline);
  188.         }
  189.     }
  190.       }
  191.       if(result[i] != NULL) result[i] = trim_junk(result[i]);
  192.     }
  193.   return(result);
  194. }
  195.  
  196. DocList ReadListOfDocuments(file)
  197. FILE *file;
  198. {
  199.   short check_result;
  200.   DocumentID documentid = NULL;
  201.   DocList result, this, last;
  202.           
  203.   /* initialize */
  204.   this = last = result = NULL;
  205.  
  206.   if(ReadStartOfList(file) == FALSE)
  207.     return(NULL);
  208.  
  209.   while(TRUE) {
  210.     documentid = (DocumentID)s_malloc(sizeof(_DocumentID));
  211.     documentid->start = -1;
  212.     documentid->end = -1;
  213.     check_result = ReadDocument(documentid, file);
  214.     if(check_result == END_OF_STRUCT_OR_LIST) {
  215.       s_free(documentid);
  216.       return(result);
  217.     }
  218.     else if(check_result == FALSE)
  219.       return(result);
  220.  
  221.     else if(check_result == TRUE) {
  222.       if(result == NULL)
  223.     result = this = (DocList)s_malloc(sizeof(_DocList));
  224.       else
  225.     this = (DocList)s_malloc(sizeof(_DocList));
  226.       this->thisDoc = documentid;
  227.       if(last != NULL)
  228.     last->nextDoc = this;
  229.       last = this;
  230.     }
  231.   }
  232. }
  233.  
  234. short
  235. ReadFragment(file, dest)
  236. FILE *file;
  237. long *dest;
  238. {
  239.   char temp_string[MAX_SYMBOL_SIZE];
  240.   short check_result;
  241.  
  242.   /* initialize */
  243.   check_result = CheckStartOfStruct("fragment", file);
  244.  
  245.   if(FALSE == check_result){ 
  246.     return(false);
  247.   }
  248.   if(END_OF_STRUCT_OR_LIST == check_result)
  249.     {
  250.       return(FALSE);
  251.     }
  252.     
  253.   /* read the slots: */
  254.   while(check_result != END_OF_STRUCT_OR_LIST){
  255.     short check_result = ReadSymbol(temp_string, file, MAX_SYMBOL_SIZE);
  256.     if(END_OF_STRUCT_OR_LIST == check_result) {
  257.       return(true);
  258.     }
  259.     if(0 == strcmp(temp_string, ":byte-pos")){
  260.       if(FALSE == ReadLong(file, dest)){
  261.     return(false);
  262.       }
  263.     }
  264.     else if(0 == strcmp(temp_string, ":line-pos")){
  265.       if(FALSE == ReadLong(file, dest)){
  266.     return(false);
  267.       }
  268.     }
  269.     else if(0 == strcmp(temp_string, ":para-id")){
  270.       if(FALSE == ReadLong(file, dest)){
  271.     return(false);
  272.       }
  273.     }
  274.     else            /* we don't know what this is */
  275.       SkipObject(file);
  276.   }
  277.   return(true);
  278. }
  279.  
  280. /* Read a document from a file.  If it is the end of a list instead of
  281.  * at a document, then return END_OF_STRUCT_OR_LIST, 
  282.  * if it hits an error on loading, return FALSE,
  283.  * otherwise return TRUE.
  284.  */
  285. short
  286. ReadDoc(file, doc)
  287. FILE *file;
  288. CRetDocument doc;
  289. {
  290.   char temp_string[MAX_SYMBOL_SIZE];
  291.   short check_result;
  292.   long lines, chars, best;
  293.   long i, numtypes = 0;
  294.   char *types[100];
  295.   DocID* docid = NULL;
  296.   SourceID aSid;
  297.   char headline[MAX_SYMBOL_SIZE];
  298.   char dateStr[MAX_SYMBOL_SIZE];
  299.           
  300.   /* initialize */
  301.   check_result = CheckStartOfStruct("document", file);
  302.   headline[0] = '\0';
  303.   dateStr[0] = '\0';
  304.  
  305.   if(FALSE == check_result){ 
  306.     return(false);
  307.   }
  308.   if(END_OF_STRUCT_OR_LIST == check_result)
  309.     {
  310.       return(FALSE);
  311.     }
  312.     
  313.   /* read the slots: */
  314.   while(check_result != END_OF_STRUCT_OR_LIST){
  315.     short check_result = ReadSymbol(temp_string, file, MAX_SYMBOL_SIZE);
  316.     if(END_OF_STRUCT_OR_LIST == check_result) {
  317.       if(*headline != 0)
  318.     doc->headline = s_strdup(headline);
  319.       doc->type = (char**)s_malloc((numtypes+1)*sizeof(char*));
  320.       for(i = 0; i < numtypes; i++)
  321.     doc->type[i] = types[i];
  322.       doc->type[numtypes] = NULL;
  323.       return(true);
  324.     }
  325.     if(FALSE == check_result){
  326.       return(false);
  327.     } 
  328.     if(0 == strcmp(temp_string, ":number-of-lines")) {
  329.       ReadLong(file,&lines);
  330.       doc->numLines = lines;
  331.     }
  332.     else if ((0 == strcmp(temp_string, ":number-of-bytes")) ||
  333.          (0 == strcmp(temp_string, ":number-of-characters"))){
  334.       ReadLong(file,&chars);
  335.       doc->numChars = chars;
  336.     }
  337.     else if(0 == strcmp(temp_string, ":best-line")){
  338.       ReadLong(file,&best);
  339.       doc->best = best;
  340.     }
  341.     else if(0 == strcmp(temp_string, ":date")){
  342.       if(FALSE == ReadString(dateStr, file, MAX_SYMBOL_SIZE)){
  343.     return(false);
  344.       }
  345.     }
  346.     else if(0 == strcmp(temp_string, ":headline")){
  347.       if(FALSE == ReadString(headline, file, MAX_SYMBOL_SIZE))
  348.     return(false);
  349.       doc->headline = s_strdup(headline);
  350.     }
  351.     else if(0 == strcmp(temp_string, ":doc-id")){
  352.       docid = (DocID*)s_malloc(sizeof(DocID));
  353.       if(FALSE == ReadDocID(docid, file)){
  354.     return(false);
  355.       }
  356.       doc->id = docid;
  357.     }
  358.     else if(0 == strcmp(temp_string, ":source")){
  359.       long return_value;
  360.       aSid = (SourceID)s_malloc(sizeof(_SourceID));
  361.       return_value = ReadSourceID(file, aSid);
  362.       if (return_value == END_OF_STRUCT_OR_LIST || return_value == false)
  363.     { s_free(aSid);
  364.       return(false);
  365.     }
  366.       doc->sourceID = aSid;
  367.     }
  368.     else if(strcmp(temp_string, ":type") == 0) {
  369.       if(FALSE == ReadString(temp_string, file, MAX_SYMBOL_SIZE))
  370.     return(false);
  371.       types[numtypes++] = s_strdup(temp_string);
  372.     }
  373.     else            /* we don't know what this is */
  374.       SkipObject(file);
  375.   }
  376.   doc->type = (char**)s_malloc((numtypes+1)*sizeof(char*));
  377.   for(i = 0; i < numtypes; i++)
  378.     doc->type[i] = types[i];
  379.  
  380.   doc->type[numtypes] = NULL;
  381.  
  382.   return(true);
  383. }
  384.  
  385. short ReadDocument(doc, file)
  386. DocumentID doc;
  387. FILE *file;
  388. {
  389.   CRetDocument document = NULL;
  390.   short status;
  391.   char temp_string[MAX_SYMBOL_SIZE];
  392.   short result = CheckStartOfStruct("document-id",file);
  393.   
  394. /*
  395.   start = end = NULL;
  396. */
  397.   doc->rawScore = doc->normalScore = -1;
  398.   
  399.   if (result == false)
  400.     return(false);
  401.   if (result == END_OF_STRUCT_OR_LIST)
  402.     return(END_OF_STRUCT_OR_LIST);
  403.     
  404.   while (TRUE)
  405.    { short check_result;
  406.      long val;
  407.      check_result = ReadSymbol(temp_string,file,MAX_SYMBOL_SIZE);
  408.  
  409.      if (check_result == false)
  410.        return(false);
  411.      if (check_result == END_OF_STRUCT_OR_LIST)
  412.        return(true);
  413.        
  414.      if (strcmp(temp_string,":score") == 0)
  415.       { if (ReadLong(file,&val) == false)
  416.           return(false);
  417.         doc->rawScore = (short)val;
  418.       }
  419.      else if (strcmp(temp_string,":document") == 0) {
  420.        document = MakeNewDocument();
  421.        status = ReadDoc(file, document);
  422.        if(status == false) {
  423.      fprintf(stderr, "error reading document structure.\n");
  424.        }
  425.        doc->doc = document;
  426.      }
  427.      else if(0 == strcmp(temp_string, ":start")){
  428.        if(FALSE == ReadFragment(file, &val))
  429.      return(false);
  430.        doc->start = val;
  431.      }
  432.      else if(0 == strcmp(temp_string, ":end")){
  433.        if(FALSE == ReadFragment(file, &val))
  434.      return(false);
  435.        doc->end = val;
  436.      }
  437.      else
  438.        SkipObject(file);
  439.    }
  440. }
  441.  
  442. CRetDocument
  443. MakeNewDocument()
  444. {
  445.   CRetDocument result;
  446.  
  447.   result = (CRetDocument)s_malloc(sizeof(_CRetDocument));
  448.   result->id = NULL;
  449.   result->sourceID = NULL;
  450.   result->myConnection= NULL;
  451.   result->numLines = 0;
  452.   result->numChars = 0;
  453.   result->blocks = result->pendingBlocks = NULL;
  454.   result->best = 0;
  455.   result->source = result->headline = result->city = NULL;
  456.   result->stock = result->company = result->industry = NULL;
  457.   result->type = NULL;
  458.   result->date = NULL;
  459.   result->next = result->prev = NULL;
  460.   result->paraStarts = NULL; /* should be array[1] = -1; */
  461.   
  462.   return(result);
  463. }
  464.  
  465.  
  466. DocList
  467. makeDocList(doc, rest)
  468. DocumentID doc;
  469. DocList rest;
  470. {
  471.   DocList result;
  472.   if((result = (DocList)s_malloc(sizeof(_DocList))) != NULL) {
  473.     result->thisDoc = doc;
  474.     result->nextDoc = rest;
  475.   }
  476.   return(result);
  477. }
  478.  
  479. static CRetDocument
  480. copy_cretdoc(doc)
  481. CRetDocument doc;
  482. {
  483.   CRetDocument result = NULL;
  484.   if(doc != NULL &&
  485.      (result = s_malloc(sizeof(_CRetDocument))) != NULL) {
  486.     result->id = copyDocID(doc->id);
  487.     result->sourceID = doc->sourceID; /* not copied - not freed! */
  488.     result->numLines = doc->numLines;
  489.     result->numChars = doc->numChars;
  490.     result->best = doc->best;
  491.     result->source = s_strdup(doc->source);
  492.     result->headline = s_strdup(doc->headline);
  493.     result->city = s_strdup(doc->city);
  494.     result->stock = s_strdup(doc->stock);
  495.     result->company = s_strdup(doc->company);
  496.     result->industry = s_strdup(doc->industry);
  497.     result->date = s_strdup(doc->date);
  498.     result->type = (char**)copyList(doc->type);
  499.   }
  500.   return result;
  501. }
  502.  
  503. DocumentID
  504. copy_docid(doc)
  505. DocumentID doc;
  506. {
  507.   DocumentID result;
  508.   
  509.   result = (DocumentID)s_malloc(sizeof(_DocumentID));
  510.   result->rawScore = doc->rawScore;
  511.   result->start = doc->start;
  512.   result->end = doc->end;
  513.   result->doc = copy_cretdoc(doc->doc);
  514.  
  515.   return result;
  516. }
  517.  
  518. void WriteDocument(doc, fp)
  519. DocumentID doc;
  520. FILE *fp;
  521. {
  522.   WriteStartOfStruct("document-id", fp);
  523.   WriteNewline(fp);
  524.   WriteSymbol(":score", fp);
  525.   WriteLong(doc->rawScore, fp);
  526.   WriteNewline(fp);
  527.   if(doc->start >= 0) {
  528.     WriteSymbol(":start", fp);
  529.     WriteNewline(fp);
  530.     WriteStartOfStruct("fragment", fp);
  531.     WriteNewline(fp);
  532.     WriteSymbol(":line-pos", fp);
  533.     WriteLong(doc->start, fp);
  534.     WriteEndOfStruct(fp);
  535.     WriteNewline(fp);
  536.   }
  537.   if(doc->end > 0) {
  538.     WriteSymbol(":end", fp);
  539.     WriteNewline(fp);
  540.     WriteStartOfStruct("fragment", fp);
  541.     WriteNewline(fp);
  542.     WriteSymbol(":line-pos", fp);
  543.     WriteLong(doc->end, fp);
  544.     WriteEndOfStruct(fp);
  545.     WriteNewline(fp);
  546.   }
  547.   if(doc->doc != NULL) {
  548.     WriteSymbol(":document", fp);
  549.     WriteNewline(fp);
  550.     WriteStartOfStruct("document", fp);
  551.     WriteNewline(fp);
  552.     if(doc->doc->headline != NULL) {
  553.       WriteSymbol(":headline", fp);
  554.       WriteString(doc->doc->headline, fp);
  555.     }
  556.     if (doc->doc->id != NULL) {
  557.       WriteNewline(fp);
  558.       WriteSymbol(":doc-id", fp);
  559.       WriteDocID(doc->doc->id, fp);
  560.       WriteNewline(fp);
  561.     }
  562.     if (doc->doc->sourceID != NULL) {
  563.       WriteSymbol(":source", fp);
  564.       WriteNewline(fp);
  565.       WriteStartOfStruct("source-id", fp);
  566.       WriteNewline(fp);
  567.       WriteSymbol(":filename", fp);
  568.       WriteString(doc->doc->sourceID->filename, fp);
  569.       WriteNewline(fp);
  570.       WriteEndOfStruct(fp);
  571.       WriteNewline(fp);
  572.     }
  573.     WriteSymbol(":number-of-lines", fp);
  574.     WriteLong(doc->doc->numLines, fp);
  575.     WriteNewline(fp);
  576.     WriteSymbol(":number-of-bytes", fp);
  577.     WriteLong(doc->doc->numChars, fp);
  578.     WriteNewline(fp);
  579.     if(doc->doc->type != NULL) {
  580.       char **doctypes;
  581.       for(doctypes = doc->doc->type;
  582.       *doctypes != NULL;
  583.       doctypes++) {
  584.     WriteSymbol(":type", fp);
  585.     WriteString(*doctypes, fp);
  586.     WriteNewline(fp);
  587.       }
  588.     }
  589.     WriteSymbol(":best-line", fp);
  590.     WriteLong(doc->doc->best, fp);
  591.     WriteNewline(fp);
  592.     if(doc->doc->date != NULL) {
  593.       WriteSymbol(":date", fp);
  594.       WriteString(doc->doc->date, fp);
  595.       WriteNewline(fp);
  596.     }
  597.     else {
  598.       WriteSymbol(":date", fp);
  599.       WriteString("0", fp);
  600.       WriteNewline(fp);
  601.     }
  602.     WriteNewline(fp);
  603.     WriteEndOfStruct(fp);
  604.   }
  605.   WriteNewline(fp);
  606.   WriteEndOfStruct(fp);
  607.   WriteNewline(fp);
  608. }
  609.  
  610. void sort_document_list(dlist)
  611. DocList dlist;
  612. {
  613.   DocList d;
  614.   DocumentID di;
  615.   Boolean Changed = TRUE;
  616.  
  617.   while(Changed) {
  618.     Changed = FALSE;
  619.     for(d = dlist; d != NULL && d->nextDoc != NULL; d = d->nextDoc)
  620.       if(d->thisDoc != NULL && d->nextDoc->thisDoc != NULL)
  621.     if(d->thisDoc->rawScore < d->nextDoc->thisDoc->rawScore) {
  622.       Changed = TRUE;
  623.       di = d->thisDoc;
  624.       d->thisDoc = d->nextDoc->thisDoc;
  625.       d->nextDoc->thisDoc = di;
  626.     }
  627.   }
  628. }
  629.       
  630. DocList
  631. findLast(dlist)
  632. DocList dlist;
  633. {
  634.   DocList d;
  635.  
  636.   if(dlist == NULL || dlist->nextDoc == NULL) return dlist;
  637.   for(d = dlist; d->nextDoc != NULL; d = d->nextDoc);
  638.   return d;
  639. }
  640.  
  641. DocumentID
  642. findDoc(dlist, number)
  643. DocList dlist;
  644. int number;
  645. {
  646.   DocList d;
  647.   int i;
  648.  
  649.   for(i = 0, d = dlist; (d != NULL) && (i < number); i++, d = d->nextDoc);
  650.  
  651.   if (d != NULL)
  652.     return(d->thisDoc);
  653.   else
  654.     return(NULL);
  655. }
  656.  
  657. DocumentID
  658. fillDocumentID(docHeader, source)
  659. WAISDocumentHeader* docHeader;
  660. SourceID source;
  661. {
  662.   DocumentID docID;
  663.  
  664.   if((docID = (DocumentID)s_malloc(sizeof(_DocumentID))) != NULL) {
  665.     docID->rawScore = docHeader->Score;
  666.     docID->start = docID->end = -1;
  667.     if((docID->doc = (CRetDocument)s_malloc(sizeof(_CRetDocument))) != NULL) {
  668.       docID->doc->sourceID = source;
  669.       /*      docID->doc->version = docHeader->VersionNumber; */
  670.       docID->doc->numLines = docHeader->Lines;
  671.       docID->doc->numChars = docHeader->DocumentLength;
  672.       docID->doc->best = docHeader->BestMatch;
  673.  
  674.       if(docHeader->Headline != NULL) {
  675.     docID->doc->headline = s_strdup(docHeader->Headline);
  676.     /*strip_lf(docID->doc->headline);*/
  677.       }
  678.       if(docHeader->Source != NULL)
  679.     docID->doc->source = s_strdup(docHeader->Source);
  680.       if(docHeader->OriginCity != NULL)
  681.     docID->doc->city = s_strdup(docHeader->OriginCity);
  682.       if(docHeader->Date != NULL)
  683.     docID->doc->date = s_strdup(docHeader->Date);
  684.       if(docHeader->Types != NULL) {
  685.     char **types = docHeader->Types;
  686.     long numtypes = 0, t;
  687.     while (*types++) numtypes++;
  688.     docID->doc->type = (char **)s_malloc((numtypes+1)*sizeof(char*));
  689.     for(types = docHeader->Types, t=0;
  690.         t < numtypes;
  691.         t++)
  692.       docID->doc->type[t] = s_strdup(types[t]);
  693.     docID->doc->type[numtypes] = NULL;
  694.       }
  695.       else {
  696.     docID->doc->type = (char **)s_malloc(2*sizeof(char*));
  697.     docID->doc->type[0] = s_strdup("TEXT");
  698.     docID->doc->type[1] = NULL;
  699.       }
  700.       if((docID->doc->id = docIDFromAny(docHeader->DocumentID))
  701.     == NULL) {
  702.     docID->doc->id = (DocID*)s_malloc(sizeof(DocID));
  703.     memset(docID->doc->id, 0, sizeof(DocID));
  704.     docID->doc->id->originalLocalID =
  705.       duplicateAny(docHeader->DocumentID);
  706.       }
  707. /*
  708.       if(docHeader->DocumentID != NULL)
  709.     docID->doc->id->originalLocalID =
  710.       duplicateAny(docHeader->DocumentID);
  711. */
  712.     }
  713.   }
  714.   return docID;
  715. }
  716.  
  717. void
  718. freeCRetDocument(doc)
  719. CRetDocument doc;
  720. {
  721.   s_free(doc->source);
  722.   s_free(doc->headline);
  723.   s_free(doc->city);
  724.   s_free(doc->stock);
  725.   s_free(doc->company);
  726.   s_free(doc->industry);
  727.   s_free(doc->date);
  728.   if(doc->type != NULL)
  729.     freeList(doc->type);
  730.   freeDocID(doc->id);
  731.   s_free(doc);
  732. }
  733.  
  734. void
  735. freeDocumentID(docID)
  736. DocumentID docID;
  737. {
  738.   if(docID != NULL) {
  739.     if(docID->doc != NULL) {
  740.       freeCRetDocument(docID->doc);
  741.     }
  742.     s_free(docID);
  743.   }
  744. }
  745.  
  746. void
  747. freeDocList(doclist)
  748. DocList doclist;
  749. {
  750.   DocList dl;
  751.   while(doclist != NULL) {
  752.     freeDocumentID(doclist->thisDoc);
  753.     dl = doclist;
  754.     doclist = doclist->nextDoc;
  755.     s_free(dl);
  756.   }
  757. }
  758.